package gang.org.springframework.boot.web.embedded.tomcat;

import gang.org.springframework.boot.autoconfigure.web.servlet.server.GangAbstractServletWebServerFactory;
import gang.org.springframework.boot.web.server.GangWebServer;
import gang.org.springframework.boot.web.servlet.GangServletContextInitializer;
import gang.org.springframework.framework.context.GangResourceLoaderAware;
import gang.org.springframework.framework.io.GangResourceLoader;
import gang.org.springframework.framework.util.GangClassUtils;
import gang.org.springframework.framework.web.servlet.GangDispatcherServlet;
import lombok.SneakyThrows;
import org.apache.catalina.*;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.loader.WebappLoader;
import org.apache.catalina.startup.Tomcat;

import java.io.File;
import java.util.Collections;
import java.util.Set;

/**
 * @Author：gang.chen
 * @Date：2023/9/25 17:41
 */
public class GangTomcatServletWebServerFactory extends GangAbstractServletWebServerFactory implements GangConfigurableTomcatWebServerFactory, GangResourceLoaderAware {

    public File baseDirectory;
    public String protocol = DEFAULT_PROTOCOL;

    public GangResourceLoader resourceLoader;

    public static final Set<Class<?>> NO_CLASSES = Collections.emptySet();
    public static final String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol";

    @Override
    public GangWebServer getWebServer(GangServletContextInitializer... initializers) {
        //if(this.disableMBeanRegistry) TODO

        Tomcat tomcat = new Tomcat();

        //File baseDir = this.baseDirectory != null ? this.baseDirectory : createTemDir("tomcat"); TODO

        //tomcat.setBaseDir(baseDir.getAbsolutePath()); TODO

        //for( LifecycleListener listener : this.serverLifecycleListeners) TODO

        Connector connector = new Connector(this.protocol);
        //connector.setThrowOnFailure(true); TODO

        tomcat.getService().addConnector(connector);

        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        //tomcat connector定制方法
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        customizeConnector(connector);

        tomcat.setConnector(connector);

        //tomcat.getHost().setAutoDeploy(false); TODO

        //configureEngine(tomcat.getEngine()) TODO

        //for(Connector additionalConnector : this.additionalTomcatConnectors)

        prepareContext(tomcat.getHost(), initializers);

        return getTomcatWebServer(tomcat);
    }

    private void customizeConnector(Connector connector) {

        int port = Math.max(getPort(), 0);
        connector.setPort(port);

        //TODO
        connector.setProperty("bindOnInit", "false");

    }


    private void prepareContext(Host host, GangServletContextInitializer[] initializers) {

        //File documentRoot = getValidDocumentRoot(); //TODO

        GangTomcatEmbeddedContext context = new GangTomcatEmbeddedContext();

        //+++++++++++++++++++++++++++参数设置+++++++++++++++++++++++++++++++++++
        context.setName("api");
        context.setPath("/api");
        context.setDocBase(null);
        context.addLifecycleListener(new Tomcat.FixContextListener());
        //+++++++++++++++++++++++++++参数设置+++++++++++++++++++++++++++++++++++

        //if(documentRoot != null) TODO

        //context.setName(getContextPath()); // TODO ""

        //context.setDisplayName(getDisplayName());//TODO "application"

        //context.setPath(getContextPath()); //TODO ""

        //File docBase = documentRoot != null ? documentRoot : createTemDir("tomcat-docbase"); TODO
        //context.setDocBase(docBase.getAbsolutePath()); TODO

        //context.addLifecycleListener(new Tomcat.FixContextListener()); TODO

        //context.setParentClassLoader(this.resourceLoader !=null ? this.resourceLoader.getClassLoader() : GangClassUtils.getDefaultClassLoader()); TODO

        //resetDefaultLocalMapping(context) TODO

        //addLocaleMappings(context) TODO

        try{
            //context.setCreateUploadTargets(true); TODO
        }catch (Exception e){
            //TODO
        }

        //configureTldPatterns(context) TODO

        //WebappLoader loader = new WebappLoader(); TODO
        //loader.setLoaderClass(GangTomcatEmbeddedWebappClassLoader.class.getName());
        //loader.setDelegate(true); TODO

        //context.setLoader(loader); TODO

        if (isRegisterDefaultServlet()) {
            //addDefaultServlet(context) TODO
        }

        //if (shouldRegisterJspServlet()) TODO

        //context.addLifecycleListener(new StaticResourceConfigure(context)) TODO

        GangServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
        host.addChild(context);
        configureContext(context, initializersToUse);
        postProcessContext(context);
    }



    private void configureContext(Context context, GangServletContextInitializer[] initializersToUse) {

        GangTomcatStarter starter = new GangTomcatStarter(initializersToUse);
        if (context instanceof GangTomcatEmbeddedContext) {

            GangTomcatEmbeddedContext embeddedContext = (GangTomcatEmbeddedContext) context;
            embeddedContext.setStarter(starter);
            embeddedContext.setFailCtxIfServletStartFails(true);
        }

        context.addServletContainerInitializer(starter, NO_CLASSES);

        //TODO

    }

    private void postProcessContext(GangTomcatEmbeddedContext context) {
        //TODO
    }

    private GangWebServer getTomcatWebServer(Tomcat tomcat) {
        return new GangTomcatWebServer(tomcat, getPort()>=0, getShutdown());
    }

    @Override
    public void setResourceLoader(GangResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }



}
